/**
 * @project: BrickCAD
 * @className: AppFrame.java
 * @package: default
 * @author: Sean , Jack, Lester, Erik Telstad
 * @date_created: November 16, 2009
 * @last_motified: November 16, 2009
 * 
 * @Class_Description:
 *      BrickCAD's main class. In this class a Main application frame is created
 *      in which all other frames (views) will be displayed.
 * 
 */


import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Iterator;

import javax.swing.JDesktopPane;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;

//import mazeChallenge.Maze;

import guiUtils.GUIUtils;

public class AppFrame extends JFrame {
    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	static String title = "BrickCAD Turbo";
	
	private String[] fileMenuItems = { 	"&New",
										"&Open",
										"&Save",
										"Save &As",
										"&Exit" 
										};
	
	private String[] viewMenuItems = { 	"&Top",
										"S&ide",
										"&Front",
										"&Data"
										};
	
	private String[] editMenuItems = { 	"&Undo",
										"&Redo",
										"Edit &Width",
										"Edit &Height",
										"Edit &Length",
										};

	private JDesktopPane desktop; 
	private JMenuBar menuBar;
	private JMenu fileMenu, viewMenu, editMenu;
	private FileMenuController fileControl = new FileMenuController();
	private ViewMenuController viewControl = new ViewMenuController();
	private EditMenuController editControl = new EditMenuController();
    protected Brick model;
    protected static CommandProcessor cmmdProc = new CommandProcessor();
    //private Command aCommand;
    protected ArrayList<BrickView> views = new ArrayList<BrickView>();
    //private int i = 0;
    
    /**
     * Constructs a JFrame that will provide the UI and hold the 
     * internal view frames.
     */
    public AppFrame(){
    	desktop = new JDesktopPane();
//        JPanel mainPanel = new JPanel();
    	setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setDefaultLookAndFeelDecorated(true);
		
        //Make the big window be indented 50 pixels from each edge
        //of the screen.
        int inset = 100;
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        setBounds(inset, inset,
                  screenSize.width/2,
                  screenSize.height/2);

		
		desktop = new JDesktopPane(); //a specialized layered pane
        setContentPane(desktop);
        
        menuBar = new JMenuBar();
        setJMenuBar(menuBar);
        
		fileMenu = GUIUtils.makeMenu("File", fileMenuItems, fileControl);
		editMenu = GUIUtils.makeMenu("Edit", editMenuItems, editControl);
		viewMenu = GUIUtils.makeMenu("View", viewMenuItems, viewControl);
		
		menuBar.add(fileMenu);
		menuBar.add(editMenu);
		menuBar.add(viewMenu);
		
		disableButtons();
		
		addWindowListener(new WindowAdapter() {

            public void windowClosing(WindowEvent e) {
                //System.out.println("Exiting the program...via x");
                int tmpQuit = -1;
                if(model != null){
                    tmpQuit = fileControl.saveChanges();
                    if ( tmpQuit == 0){
                        fileControl.save(false);
                        fileControl.closeViews();
                    }
                    else if(tmpQuit == 1)
                        fileControl.closeViews();
                }
                if(tmpQuit != 2){
                    //System.out.println(tmpQuit);
                    System.exit(0);
                    }
            }
         });
    }
    
    private void enableButtons() {
        fileMenu.getItem(2).setEnabled(true);
        fileMenu.getItem(3).setEnabled(true);
        
        for(int i=0; i < editMenuItems.length; i++){
            editMenu.getItem(i).setEnabled(true);
        }
    
        for(int i=0; i < viewMenuItems.length; i++){
            viewMenu.getItem(i).setEnabled(true);
        }
    }
    
    private void disableButtons() {
        fileMenu.getItem(2).setEnabled(false);
        fileMenu.getItem(3).setEnabled(false);
        
        for(int i=0; i < editMenuItems.length; i++){
            editMenu.getItem(i).setEnabled(false);
        }
    
        for(int i=0; i < viewMenuItems.length; i++){
            viewMenu.getItem(i).setEnabled(false);
        }
    }
    
	/**
	 * @author Sean O'Brien
	 * 
	 * FileMenuController - an inner class of the application frame that
	 * handles action events generated by the file menu.
	 *
	 */
	class FileMenuController implements ActionListener {

		private File currentDir;
		
		/**
		 * Asks user if model should be saved
		 * @return true if yes
		 */
		private int saveChanges() {
			if (!model.isChanged()) return 1;
			int choice = JOptionPane.showConfirmDialog(AppFrame.this, "Save changes?");
			return choice;
		}

		/**
		 * Saves model to selected file.
		 * @param saveAs prompt user for new file if true
		 */
		private void save(boolean saveAs) {
			if (!saveAs && !model.isChanged()) return; // nothing to do
			File f = model.getFile();
			if (f == null || saveAs) {
				f = getFileSave();
				model.setFile(f);
			}
			try {
				ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
				oos.writeObject(model);
				model.setChanged(false);
			} catch(Exception e) {
				GUIUtils.error(e.getMessage());
			}
		}

		/**
		 * Prompts user for file to be saved or open
		 * @return the selected file
		 */
		private File getFile() {
			 JFileChooser chooser = new JFileChooser();
			 if (currentDir != null) {
				 chooser.setCurrentDirectory(currentDir);
			 }
			 chooser.showOpenDialog(AppFrame.this);
			 File result = chooser.getSelectedFile();
			 if(result != null){
			     currentDir = result.getParentFile();
			 }
			 return result;
		}

		private File getFileSave() {
			 JFileChooser chooser = new JFileChooser();
			 if (currentDir != null) {
				 chooser.setCurrentDirectory(currentDir);
			 }
			 chooser.showSaveDialog(AppFrame.this);
			 File result = chooser.getSelectedFile();
			 currentDir = result.getParentFile();
			 return result;
		}

		/**
		 * Replaces existing model with model read from selected file.
		 */
		private void open() {
			File f = getFile();
			try {
				ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));
				Brick savedBrick = (Brick)ois.readObject();
				model = savedBrick;
			} catch(NullPointerException e){
			    
		    } catch(Exception e) {
				GUIUtils.error(e.getMessage());
			}
		}

		private void closeViews() {
			views.trimToSize();
			Iterator<BrickView> iter = views.iterator();
			while(iter.hasNext())
				iter.next().dispose();
			views.clear();
		}
		
		public void actionPerformed(ActionEvent e) {
			String cmmd = e.getActionCommand();
	        if(cmmd.equals("Exit")) { //exit
	        	//System.out.println("Exiting the program...");
	            int tmpQuit = -1;
				if(model != null) {
				    tmpQuit = saveChanges();
					if (tmpQuit == 0){
					    save(false);
					    closeViews();
					}
					else if(tmpQuit == 1)
					    closeViews();
				}
				if(tmpQuit != 2)
				    System.exit(0);
	        	
	        }
			if (cmmd.equals("New")) { //new
	        	//System.out.println("Creating a New Brick file...");
			    int tmpQuit = -1;
			    if(model != null) {
			        tmpQuit =  saveChanges();
                    if (tmpQuit == 0){
                        save(false);
                        closeViews();
                    }
                    else if(tmpQuit == 1)
                        closeViews();
                }
                else
                    enableButtons();
                if(tmpQuit != 2)
                    model = new Brick();

			}else if (cmmd.equals("Save")) { //save
	        	//System.out.println("Saving a Brick file...");
				if(model != null) {
					save(false);
				}
        	
	        }else if(cmmd.equals("Save As")) { //save as
	        	//System.out.println("Saving a Brick file As...");
				if(model != null) {
					save(true);
				}

	        }else if(cmmd.equals("Open")) { //open
	        	//System.out.println("Opening a Brick file...");
	            int tmpQuit = -1;
                if(model != null) {
                    tmpQuit = saveChanges();
                    if (tmpQuit == 0){
                        save(false);
                        closeViews();
                    }
                    else if(tmpQuit == 1)
                        closeViews();
                }
                if (tmpQuit != 2)
                    open();
	        }else  { // unrecognized command
				GUIUtils.error("unrecognized command: " + cmmd);
			}
		}
	}

	/**
	 * @author Sean O'Brien
	 * 
	 * ViewMenuController - an inner class of the application frame that
	 * handles action events generated by the view menu.
	 *
	 */
	class ViewMenuController implements ActionListener {
		public void actionPerformed(ActionEvent e) {
	        String cmmd = e.getActionCommand();
	        if(model != null)
	        	createView(cmmd);
		}
	}

    //Create a new internal frame.
    public void createView(String view) {
   		if(view.equals("Data")) 
   			views.add(new DimensionView(model));
   		else if(view.equals("Top"))
   			views.add(new TopView(model));
   		else if(view.equals("Front"))
   			views.add(new FrontView(model));
   		else if(view.equals("Side"))
   			views.add(new SideView(model));
   		int lastIndex = views.size() - 1;
   		views.get(lastIndex).setVisible(true); //necessary as of 1.3
   		desktop.add(views.get(lastIndex));
   		try {
   			views.get(lastIndex).setSelected(true);
   		} catch (java.beans.PropertyVetoException e) {
   			
   		}catch(NullPointerException npe) {
   			//JOptionPane.showMessageDialog(AppFrame.this, npe.getMessage());
   		}
    }


	/**
	 * @author Sean O'Brien
	 * 
	 * EditMenuController - an inner class of the application frame that
	 * handles action events generated by the edit menu.
	 *
	 */
	class EditMenuController implements ActionListener {
		
		private double getValue(String prompt, double initValue) 
			/*throws NullPointerException*/ { 
			
			String response = JOptionPane.showInputDialog(AppFrame.this, prompt, initValue);
				return new Double(response);
		}

		public void actionPerformed(ActionEvent e) {
			String cmmd = e.getActionCommand();
			double value = 0;
			try {
				if(cmmd.equals("Edit Height")) {
					value = getValue("Enter height", model.getHeight());
					//aCommand = new SetHeightCommand(value);
					cmmdProc.execute(new SetHeightCommand(value));
				} else if(cmmd.equals("Edit Width")) {
					value = getValue("Enter width", model.getWidth());
					//aCommand = new SetWidthCommand(value);
					cmmdProc.execute(new SetWidthCommand(value));
				} else if(cmmd.equals("Edit Length")) {
					value = getValue("Enter length", model.getLength());
					//aCommand = new SetLengthCommand(value);
					cmmdProc.execute(new SetLengthCommand(value));
				} else if(cmmd.equals("Redo")) {
					cmmdProc.redo();
				} else if(cmmd.equals("Undo")) {
					cmmdProc.undo();
				}
				
			} catch(NumberFormatException nfe) {
				JOptionPane.showMessageDialog(AppFrame.this, nfe.getMessage());
			} catch(IllegalArgumentException iae) {
				JOptionPane.showMessageDialog(AppFrame.this, iae.getMessage());
			} catch(NullPointerException npe) {
				//JOptionPane.showMessageDialog(AppFrame.this, "No Brick To Edit");
			}
		}
	}

	public static void main(String[] args) {
        AppFrame frame = new AppFrame();
        //frame.setSize(500, 500);
//        frame.setLocation(x, y)
        frame.setTitle(title);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
       }

}
